package com.lz.yz.member.service.impl;


import com.google.common.base.CaseFormat;
import com.lz.yz.base.entity.ReturnValue;
import com.lz.yz.member.dao.AccountMapper;
import com.lz.yz.member.entity.Account;
import com.lz.yz.member.enumeration.AccountField;
import com.lz.yz.member.enumeration.AccountType;
import com.lz.yz.member.model.AccountModel;
import com.lz.yz.member.model.RequestUser;
import com.lz.yz.member.model.ResponseAccount;
import com.lz.yz.member.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private TokenGenerator tokenGenerator;

    @Resource(name = "redisTemplate")
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 用户登陆
     */
    @Override
    public ReturnValue validateAndLogin(RequestUser user) {
        Account loginAccount = this.doLogin(AccountField.Name, user.getPhone(), user.getPassword(), AccountType.Admin.value()+"");
        if (loginAccount == null) {
            return ReturnValue.generateFalseReturnValue("账号或密码错误");
        }
        ResponseAccount model = new ResponseAccount(loginAccount.getId());
        BeanUtils.copyProperties(loginAccount, model);
        return ReturnValue.generateTrueReturnValue(model);
    }


    void updateLoginInfo(AccountModel model) {
        // 更新登录时间和ip
        Date now = new Date();
        // 若 token 过期则更新
        if (!isTokenValid(model)) {
            String token = tokenGenerator.genToken();
            Date expireAt = tokenGenerator.genExpireDate(now);
            model.setToken(token);
            model.setExpireAt(expireAt);
        }
    }

    /**
     * 检查 AccountModel 对象中的 token 是否有效,是否过期
     */
    boolean isTokenValid(AccountModel model) {
        if (null != model.getToken()
                && null != model.getExpireAt()
                && model.getExpireAt().after(new Date())) {
            return true;
        }
        return false;
    }

    /**
     * 将 AccountField 枚举转换为对应的 db column 名
     */
    String enumToColumn(AccountField type) {
        return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, type.name());
    }

    /**
     * Account 的缓存 key 格式: account:TOKEN
     */
    String cacheKey(String token) {
        return "account:" + token;
    }

    /**
     * 将 Account 写入缓存并设置过期时间(如果已禁用或被软删则删除缓存)
     */
    void writeToCache(Account account) {
        ValueOperations<String, Object> ops = redisTemplate.opsForValue();
        long expire = (account.getExpireAt().getTime() - (new Date()).getTime()) / 1000;
        if (expire <= 0 || account.getDeletedAt() != null) {
            redisTemplate.delete(cacheKey(account.getToken()));
        } else {
            ops.set(cacheKey(account.getToken()), account, (int) expire, TimeUnit.SECONDS);
        }
    }


    public Account doLogin(AccountField field, String accountStr,
                           String password,String types) {
        Map<String,Object> param=new HashMap<>();
        param.put("types",types);
        param.put(enumToColumn(field),accountStr);
        AccountModel model = accountMapper.selectByCond(param);
        String showAccount = field.name() + " " + accountStr;
        if (null == model) {
            logger.debug(String.format("账号%s不存在", showAccount));
            return null;
        }

        updateLoginInfo(model);
        Account update=new Account();
        BeanUtils.copyProperties(model, update);
        if (1 != accountMapper.updateByPrimaryKeySelective(update)) {
            throw new RuntimeException(String.format("账号%s更新登录信息失败", showAccount));
        }
        Account account = new Account();
        BeanUtils.copyProperties(model, account);
        writeToCache(account);
        return account;
    }
}
